﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace Asol.Reporting.Support
{
    /// <summary>
    /// Extenze datových tříd
    /// </summary>
    public static class Extensions
    {
        #region Type
        /// <summary>
        /// Vrátí true, pokud typ this je potomkem daného typu, nebo dokonce jde přímo o daný typ.
        /// Pokud ale je zadán typ předka ancestorType = null, pak vrací false (nikdo není potomkem od null typu).
        /// </summary>
        /// <param name="me"></param>
        /// <param name="ancestorType"></param>
        /// <returns></returns>
        public static bool IsDescendantOf(this Type me, Type ancestorType)
        {
            if (ancestorType == null) return false;
            Type test = me;
            while (test != null)
            {
                if (test == ancestorType) return true;
                test = test.BaseType;
            }
            return false;
        }
        /// <summary>
        /// Vrátí Namespace.Name.
        /// Pozor u vnořených tříd (tj. když je class definovaná uvnitř třídy), pak NsName nereflektuje DeclaringClass.
        /// Pokud třída LoginForm v namespace Asol.Reporting uvnitř sebe deklaruje vnořenou třídu LoginData, 
        /// pak její FullName = "Asol.Reporting.LoginForm+LoginData", ale NsName() = "Asol.Reporting.LoginData", bez toho "LoginForm+".
        /// </summary>
        /// <param name="type"></param>
        /// <returns></returns>
        public static string NsName(this Type type)
        {
            return type.Namespace + "." + type.Name;
        }
        #endregion
        #region Nullable<T>
        /// <summary>
        /// Porovná dva objekty typu Nullable.
        /// Pokud jeden z objektů je NULL a druhý není, pak NULL objekt považuje za menší.
        /// Třídění takovým komparátorem zařadí NULL objekty na začátek seznamu.
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="a"></param>
        /// <param name="b"></param>
        /// <returns></returns>
        public static int CompareTo<T>(this Nullable<T> a, Nullable<T> b) where T : struct, IComparable
        {
            if (!a.HasValue && !b.HasValue) return 0;
            if (!a.HasValue) return -1;
            if (!b.HasValue) return 1;
            return a.Value.CompareTo(b.Value);
        }
        /// <summary>
        /// Porovná dva objekty typu Nullable.
        /// Pokud jeden z objektů je NULL a druhý není, 
        /// pak NULL objekty řadí podle parametru: bool nullToEnd: true = na konec, false = na začátek.
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="a"></param>
        /// <param name="b"></param>
        /// <param name="nullToEnd">Pořadí hodnoty NULL proti hodnotě HasValue: true = NULL bude na konci, false = NULL bude na začátku</param>
        /// <returns></returns>
        public static int CompareTo<T>(this Nullable<T> a, Nullable<T> b, bool nullToEnd) where T : struct, IComparable
        {
            if (!a.HasValue && !b.HasValue) return 0;
            if (!a.HasValue) return (nullToEnd ? 1 : -1);
            if (!b.HasValue) return (nullToEnd ? -1 : 1);
            return a.Value.CompareTo(b.Value);
        }
        #endregion
    }
}
